#include "TcpConnection.hpp"
#include "EventLoop.hpp"      // TcpConnection.hpp有头文件保护，不会重复引入

// SocketIO 类 -------------------------------------------------------------
SocketIO::SocketIO(int fd)
: _fd(fd)
{}

SocketIO::~SocketIO()
{
    // TcpConnection会同时持有SocketIO和Socket，这两个socket的fd都是同一个，
    // 所以在TcpConnection析构时，只需要关闭Socket的fd即可，SocketIO的fd会随之自动关闭
    // close(_fd);
}
  // recv函数单次读取的数据量存在上限
size_t SocketIO::readn(char *buf, size_t len){  
    size_t total = 0;
    size_t ret = 0;
    while(total < len){
        ret = ::recv(_fd, buf + total, len - total, MSG_DONTWAIT);  // 非阻塞
        if(ret < 0 && errno == EINTR){ // 进程（线程）被信号中断
            continue;  
        }
        else if(ret < 0){  // 其他错误
            throw "recv error";
        }
        else if(ret == 0){  // 对端关闭连接
            break;  
        }
        else{  // 正常读取到数据
            total += ret;  
        }
    }
    return total;  // 返回读取到的总字节数
}   
   // "send" has an upper limit on data amount that can be written in a single operation
size_t SocketIO::writen(const char *buf, size_t len){ // 
    size_t total = 0;
    size_t ret = 0;
    while(total < len){
        ret = ::send(_fd, buf + total, len - total, MSG_DONTWAIT); // non-blocking
        if(ret < 0 && errno == EINTR){ // interrupted system call
            continue;  
        }
        else if(ret < 0){  // other errors
            throw "send error";
        }
        else if(ret == 0){  // connection closed on the other side
            break;  
        }
        else{  // successfully sent
            total += ret;
        }
    }
    return total;  // return the total bytes sent
}   
    // 最多读取len-1个字节，最后一个字节留给'\0'
size_t SocketIO::readline(char *buf, size_t len){ // 问题：当该函数所读取内容中没有换行符时会被阻塞！！
    size_t total = 0;
    size_t ret = 0;
    while(total < len - 1){
        //MSG_PEEK不会将socket缓冲区中的数据进行清空，只会进行拷贝操作
        ret = ::recv(_fd, buf + total, len - 1 - total, MSG_PEEK);  
        if(ret < 0 && errno == EINTR){ // 进程（线程）被信号中断
            continue;  
        }
        else if(ret < 0){  // 其他错误
            throw "recv error";
        }
        else if(ret == 0){  // 对端关闭连接
            break;  
        }
        else{  // 正常peek到数据
            // 查找换行符:
            for(size_t i = total; i < total + ret; ++i){ 
                if(buf[i] == '\n'){
                    readn(buf + total, i + 1); // 真正从socket缓冲区取走数据
                    total += i;         // 换行符没有计入total
                    buf[total] = '\0';  // 将换行符替换为'\0'
                    return total;
                }
            }
            // 未找到换行符:
            readn(buf + total, ret);  // 真正从socket缓冲区取走数据
            total += ret;
        }
    }
    buf[total] = '\0';
    return total;
}       


// TcpConnection 类 -------------------------------------------------------------
TcpConnection::TcpConnection(int fd, EventLoop * loop)
: _sockio(fd)
, _sock(fd)
, _localAddr(getLocalAddr())
, _peerAddr(getPeerAddr())
, _loop(loop)
{}

TcpConnection::~TcpConnection(){
    // 成员子对象会自动析构
}

string TcpConnection::toString() const{
    std::ostringstream os;
    os << _localAddr.getIp() << ":" << _localAddr.getPort() 
       << " ---> "
       << _peerAddr.getIp() << ":" << _peerAddr.getPort();
    return os.str();
}

string TcpConnection::peerToString() const{
    std::ostringstream os;
    os << _peerAddr.getIp() << ":" << _peerAddr.getPort();
    return os.str();
}

void TcpConnection::send(const string &msg){
    _sockio.writen(msg.c_str(), msg.size());
}

string TcpConnection::recv(){
    std::unique_ptr<char[]> buf(new char[512]);
    _sockio.readline(buf.get(), 512);
    return string(std::move(buf.get()));
}

bool TcpConnection::isClosed() const{
    char buf[5];
    int ret = ::recv(_sock.getFd(), buf, 5, MSG_PEEK);
    return ret == 0;
}

void TcpConnection::setNewConnectionCallback(TcpConnectionCallback & cb){
    _onNewConnection = cb;
}

void TcpConnection::setMessageCallback(TcpConnectionCallback & cb){
    _onMessage = cb;
}

void TcpConnection::setCloseCallback(TcpConnectionCallback & cb){
    _onClose = cb;
}

void TcpConnection::handleNewConnectionCallback(){
    if(_onNewConnection){
        _onNewConnection(shared_from_this());
    }
    else{
        cout << "_onNewConnection is invalid." << endl;
    }
}

void TcpConnection::handleMessageCallback(){
    if(_onMessage){
        _onMessage(shared_from_this());
    }
    else{
        cout << "_onMessage is invalid." << endl;
    }
}

void TcpConnection::handleCloseCallback(){
    if(_onClose){
        _onClose(shared_from_this());
    }
    else{
        cout << "_onClose is invalid." << endl;
    }
}

void TcpConnection::sendInLoop(const string &msg){
    // 将（send行为，tcp连接对象，处理好的msg）打包好，传递给主线程
    if(_loop){
        _loop->runInLoop(std::bind(&TcpConnection::send, this, msg));
    }
    else{
        cout << "sendInLoop error: no eventloop" << endl;
    }
}

InetAddress TcpConnection::getLocalAddr(){
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    int ret = ::getsockname(_sock.getFd(), (struct sockaddr *)&addr, &len);
    if(ret < 0){
        throw "getsockname error";
    }
    return InetAddress(addr);
}
 
InetAddress TcpConnection::getPeerAddr(){
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    int ret = ::getpeername(_sock.getFd(), (struct sockaddr *)&addr, &len);
    if(ret < 0){
        throw "getpeername error";
    }
    return InetAddress(addr);
}